<?php
/*
 * Copyright (c) Taras Kudla, 2010
 */

class session extends kernel {
	
    private $sid = null;
    private $session_timeout = 3600;
    private $UserAgent = null;
    private $RemoteAddr = null;
    private $AlternativeStore = false; # For ex. mysql is master dbo store engine, postgresql for session data;
    private $dbo = null;
    # session data array
    private $SESSION = array();
    public  $session_lifespan = 0;
    private $GuestOnline = array();
    private $UsersOnline = array();
    private $SessionName = _SESSION_NAME;
    
    public function init(){
		$this->SessionName = $this->core->get("sessionname");
		$starttime = microtime(1);
		if ($this->AlternativeStore != false){
			$store = $this->AlternativeStore;
		if (isset($this->core->dbo->$store) && is_object($this->core->dbo->$store)){
			$this->dbo =& $this->core->dbo->$store;
		}else{
			$this->core->error("SESSION", "Cannot load '" . $this->$store . "' as session store engine");
		}
		}else{
			$this->dbo =& $this->core->dbo;
		}
		$this->UserAgent = (isset($_SERVER["HTTP_USER_AGENT"]) ? $this->core->escapeString($_SERVER["HTTP_USER_AGENT"]) : "Undefined");
		$this->RemoteAddr = (isset($_SERVER["REMOTE_ADDR"]) ? $this->core->escapeString($_SERVER["REMOTE_ADDR"]) : "Undefined");
		if ($this->core->get("runmode") == _CONSOLE_RUNMODE)
			return false;
		# clearing all timeouted sessions
		$this->ClearSessions();
		# starting session
		$this->SessionStart();
		# checking who is online
		$this->checkOnline();
		$this->core->profiler("SESSION","User session started '".$this->sid."' ",$starttime);
	}

	public function ID(){
		$a = $this->RemoteAddr . $this->UserAgent;
		return strtoupper(md5($a . microtime(true)));
	}
	
	public function CheckCookie(){
		/**
		 * 
		 */
		if (!isset($_COOKIE[$this->SessionName]) || !preg_match("/^([A-Z0-9]{32})$/", $_COOKIE[$this->SessionName], $tmp)){
			$this->sid = $this->ID();
		} else {
			$this->sid = $this->core->escapeString($_COOKIE[$this->SessionName]);
		}
		return true;
	}

	public function SessionStart(){
		/**
		 * 
		 */
		# checking cookie
		$this->CheckCookie();
		# creating user fingerprint
		$usertrace = md5($this->UserAgent.$this->RemoteAddr);
		$session = $this->dbo->select("users_session", "lifetime,usertrace,user_id", " where session_id='" . $this->sid . "' limit 1 offset 0", _RESULT_ROW);
		$userid = 0;
		if (count($session) == 0){
			$this->dbo->insert("users_session", array(
				"session_id" => $this->sid,
				"created" => date("U"),
				"last_impression" => date("U"),
				"usertrace" => $usertrace,
				"user_id"=>0,
				"user_agent" =>$this->UserAgent
			));
		} else {
			$userid = (int)$session["user_id"];
			$this->dbo->update("users_session", " set last_impression='" . date("U") . "',online='1' where session_id='" . $this->sid . "'");
			$this->session_lifespan = $session["lifetime"];
			if( $session["usertrace"]!=$usertrace && $userid!=0 ) {
				# session capturing detected
				$this->core->log->write("SESSION: session capturing from other side detected, making new for " . $this->sid,_LOG_CRITICAL);
				$this->ClearSession($this->sid);
				# Creating new record in session table
				$this->dbo->insert("users_session", array(
					"session_id" => $this->sid,
					"created" => date("U"),
					"last_impression" => date("U"),
					"usertrace" => $usertrace,
					"user_agent" => $this->UserAgent
					));
			}
		}
		# clearing for all my last impressions
		setcookie($this->SessionName, $this->sid, $this->session_lifespan, "/");
		$this->SessionRead();
		# checking for multi session access
		if( !$this->core->get("multiaccess") && $userid!=0){
			# clearing all previous
			$this->core->dbo->delete("users_session", "where session_id!='" . $this->sid . "' and user_id='" . $userid . "'");
		}
	}
	
	private function GetVarPrefix(){
		return null;
	}

	public function get($key){
		$key=$this->GetVarPrefix().$key;
		return isset($this->SESSION[$key]) ? $this->SESSION[$key] : false;
	}	
	
	public function set($key,$value){
		$key=$this->GetVarPrefix().$key;
		$this->SESSION[$key] = $value;
	}	
	
	public function exists($key){
		$key = $this->GetVarPrefix() . $key;
		return isset($this->SESSION[$key]) ? true : false;
	}

    public function delete($key){
		$key = $this->GetVarPrefix() . $key;
		$this->SESSION[$key] = null;
		unset($this->SESSION[$key]);
	}
	
	private function checkOnline(){
		$this->dbo->update("users_session", " set online='0' where users_session.last_impression<'" . (date("U") - $this->session_timeout) . "'");
	}

	public function SessionRead(){
		$Query = $this->dbo->select("users_session_variable", "data", " where session_id='" . $this->sid . "' limit 1 offset 0", _RESULT_ROW);
		if (count($Query) == 1 && !empty($Query["data"])){
			$this->SESSION = unserialize($Query["data"]);
		}
		return true;
	}

	public function SessionWrite(){
		$query = $this->dbo->select("users_session_variable", "session_id", " where session_id='" . $this->sid . "' limit 1 offset 0");
		$data = serialize($this->SESSION);
		if (count($query) == 1){
			$this->dbo->update("users_session_variable", " set data='" . $data . "' where session_id='" . $this->sid . "'");
		} else {
			$this->dbo->insert("users_session_variable", array(
				"session_id" => $this->sid,
				"data" => $data));
		}
	}

	public function SessionClose(){
		if ($this->core->get("runmode") == _CONSOLE_RUNMODE)
			return null;
		$this->core->DEBUG("SESSION", "Closing session for " . $this->sid);
		$this->SessionWrite();
		return true;
	}

	public function ClearSessions(){
		# clearing all guests
		$this->dbo->delete("users_session", " where last_impression<'" . (date("U") - $this->session_timeout) . "' and lifetime='0'");
		# clearing by timeout setted lifetime
		$this->dbo->delete("users_session", "where lifetime!='0' and lifetime<" . date("U"));
		# clearing all data of non-existed sessions
		$this->dbo->delete("users_session_variable", " where session_id NOT IN (SELECT session_id from users_session)");
		return null;
	}

	public function ResetSessionLifetime($time){
		if ($this->core->user->CheckUser()){
			$time = time() + 80000 + $time;
			$this->dbo->update("users_session", "set lifetime='" . $time . "' where session_id='" . $this->sid . "'");
		}
	}

	private function ClearSession($sid){
		$this->dbo->delete("users_session", " where session_id='" . $sid . "' ");
		$this->dbo->delete("users_session_variable", " where session_id='" . $sid . "'");
	}
	
	public function destroymysession(){
		$this->dbo->delete("users_session", " where session_id='" . $this->sid . "' ");
		$this->dbo->delete("users_session_variable", " where session_id='" . $this->sid . "'");  	
	}

	public function &GetSid(){
		return $this->sid;
	}

	public function GetSessionName(){
		return $this->SessionName;
	}

	public function GetOnline(){
		$this->onlineusers = $this->core->dbo->select("users_session", "user_id", " where online='1' and user_id!='0'", _RESULT_LIST);
	}

	public function CheckUserOnline($id){
		return @in_array($id, $this->onlineusers);
	}
	public function void(){
	}  

}
?>